package com.example.project.utils;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 文本相似度计算工具类
 */
public class SimilarTextUtil {

    /**
     * 计算两个字符串的相似度（0-1之间）
     * 使用编辑距离算法计算相似度
     * 
     * @param s1 字符串1
     * @param s2 字符串2
     * @return 相似度（0-1之间，1表示完全相同）
     */
    public static double similarity(String s1, String s2) {
        if (s1 == null || s2 == null) {
            return 0.0;
        }
        
        if (s1.equals(s2)) {
            return 1.0;
        }
        
        // 转换为小写
        s1 = s1.toLowerCase();
        s2 = s2.toLowerCase();
        
        // 计算编辑距离
        int editDistance = levenshteinDistance(s1, s2);
        
        // 计算最大长度
        int maxLength = Math.max(s1.length(), s2.length());
        
        if (maxLength == 0) {
            return 1.0;
        }
        
        // 计算相似度
        return 1.0 - ((double) editDistance / maxLength);
    }
    
    /**
     * 计算两个字符串的编辑距离
     * 
     * @param s1 字符串1
     * @param s2 字符串2
     * @return 编辑距离
     */
    public static int levenshteinDistance(String s1, String s2) {
        int[][] dp = new int[s1.length() + 1][s2.length() + 1];
        
        for (int i = 0; i <= s1.length(); i++) {
            dp[i][0] = i;
        }
        
        for (int j = 0; j <= s2.length(); j++) {
            dp[0][j] = j;
        }
        
        for (int i = 1; i <= s1.length(); i++) {
            for (int j = 1; j <= s2.length(); j++) {
                if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = 1 + Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]);
                }
            }
        }
        
        return dp[s1.length()][s2.length()];
    }
    
    /**
     * 计算Jaccard相似度
     * 
     * @param s1 字符串1
     * @param s2 字符串2
     * @return Jaccard相似度
     */
    public static double jaccardSimilarity(String s1, String s2) {
        Set<String> set1 = getWordsSet(s1);
        Set<String> set2 = getWordsSet(s2);
        
        if (set1.isEmpty() && set2.isEmpty()) {
            return 1.0;
        }
        
        Set<String> intersection = new HashSet<>(set1);
        intersection.retainAll(set2);
        
        Set<String> union = new HashSet<>(set1);
        union.addAll(set2);
        
        return (double) intersection.size() / union.size();
    }
    
    /**
     * 计算余弦相似度
     * 
     * @param s1 字符串1
     * @param s2 字符串2
     * @return 余弦相似度
     */
    public static double cosineSimilarity(String s1, String s2) {
        Map<String, Integer> vector1 = getWordFrequency(s1);
        Map<String, Integer> vector2 = getWordFrequency(s2);
        
        Set<String> allWords = new HashSet<>();
        allWords.addAll(vector1.keySet());
        allWords.addAll(vector2.keySet());
        
        double dotProduct = 0.0;
        double norm1 = 0.0;
        double norm2 = 0.0;
        
        for (String word : allWords) {
            int freq1 = vector1.getOrDefault(word, 0);
            int freq2 = vector2.getOrDefault(word, 0);
            
            dotProduct += freq1 * freq2;
            norm1 += freq1 * freq1;
            norm2 += freq2 * freq2;
        }
        
        if (norm1 == 0 || norm2 == 0) {
            return 0.0;
        }
        
        return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }
    
    /**
     * 从字符串中提取单词集合
     * 
     * @param text 文本
     * @return 单词集合
     */
    private static Set<String> getWordsSet(String text) {
        Set<String> words = new HashSet<>();
        if (text == null || text.isEmpty()) {
            return words;
        }
        
        String[] split = text.toLowerCase().split("\\s+");
        for (String word : split) {
            if (!word.isEmpty()) {
                words.add(word);
            }
        }
        
        return words;
    }
    
    /**
     * 从字符串中提取单词频率
     * 
     * @param text 文本
     * @return 单词频率映射
     */
    private static Map<String, Integer> getWordFrequency(String text) {
        Map<String, Integer> wordFreq = new HashMap<>();
        if (text == null || text.isEmpty()) {
            return wordFreq;
        }
        
        String[] split = text.toLowerCase().split("\\s+");
        for (String word : split) {
            if (!word.isEmpty()) {
                wordFreq.put(word, wordFreq.getOrDefault(word, 0) + 1);
            }
        }
        
        return wordFreq;
    }
    
    /**
     * 综合相似度计算，结合多种算法
     * 
     * @param s1 字符串1
     * @param s2 字符串2
     * @return 综合相似度
     */
    public static double combinedSimilarity(String s1, String s2) {
        double levenshtein = similarity(s1, s2);
        double jaccard = jaccardSimilarity(s1, s2);
        double cosine = cosineSimilarity(s1, s2);
        
        // 权重分配：编辑距离40%，Jaccard 30%，余弦相似度30%
        return levenshtein * 0.4 + jaccard * 0.3 + cosine * 0.3;
    }
}